package config

import (
	"go-pan/internal/model"
	"strings"

	"go.uber.org/zap"
	"gorm.io/driver/postgres"
	"gorm.io/gorm"
)

var DB *gorm.DB
var SystemLogger *zap.Logger

// InitDatabase 初始化数据库连接
func InitDatabase() {
	if Cfg == nil {
		panic("config not initialized, please call Init() first")
	}

	dsn := GetDSN()
	// 配置 GORM：禁用外键检查，避免迁移时的约束冲突
	// 注意：GORM 可能会尝试删除不存在的约束，如果约束已经在数据库中正确创建，这些错误可以忽略
	db, err := gorm.Open(postgres.Open(dsn), &gorm.Config{
		DisableForeignKeyConstraintWhenMigrating: true,  // 禁用迁移时的外键约束检查
		PrepareStmt:                              false, // 暂时禁用预编译语句，避免某些兼容性问题
	})
	if err != nil {
		if SystemLogger != nil {
			SystemLogger.Fatal("failed to connect database", zap.Error(err))
		}
		panic("failed to connect database: " + err.Error())
	}
	SystemLogger.Info("database connection established",
		zap.String("host", Cfg.Database.Host),
		zap.Int("port", Cfg.Database.Port),
		zap.String("dbname", Cfg.Database.DBName))

	// 自动迁移模型（保持与结构同步）
	// 注意：GORM 的 AutoMigrate 可能会尝试删除不存在的约束，这是正常行为
	// 如果约束已经在数据库中正确创建，这些错误可以忽略
	SystemLogger.Info("running database migrations")

	// 辅助函数：检查错误是否为可忽略的约束错误
	isIgnoreableError := func(err error) bool {
		if err == nil {
			return false
		}
		errStr := err.Error()
		// 忽略尝试删除不存在约束的错误（约束已在数据库中存在）
		return strings.Contains(errStr, "does not exist") &&
			strings.Contains(errStr, "constraint") &&
			strings.Contains(errStr, "DROP CONSTRAINT")
	}

	migrationErrors := []error{}

	// 迁移token黑名单表
	if err := db.AutoMigrate(&model.TokenBlacklist{}); err != nil {
		if isIgnoreableError(err) {
			SystemLogger.Debug("TokenBlacklist model migration: ignored constraint error", zap.Error(err))
		} else {
			SystemLogger.Warn("TokenBlacklist model migration warning", zap.Error(err))
			migrationErrors = append(migrationErrors, err)
		}
	}

	if err := db.AutoMigrate(&model.User{}); err != nil {
		if isIgnoreableError(err) {
			SystemLogger.Debug("User model migration: ignored constraint error (constraint already exists)", zap.Error(err))
		} else {
			SystemLogger.Warn("User model migration warning", zap.Error(err))
			migrationErrors = append(migrationErrors, err)
		}
	}
	if err := db.AutoMigrate(&model.FileMetadata{}); err != nil {
		if isIgnoreableError(err) {
			SystemLogger.Debug("FileMetadata model migration: ignored constraint error", zap.Error(err))
		} else {
			SystemLogger.Warn("FileMetadata model migration warning", zap.Error(err))
			migrationErrors = append(migrationErrors, err)
		}
	}
	if err := db.AutoMigrate(&model.FileChunk{}); err != nil {
		if isIgnoreableError(err) {
			SystemLogger.Debug("FileChunk model migration: ignored constraint error", zap.Error(err))
		} else {
			SystemLogger.Warn("FileChunk model migration warning", zap.Error(err))
			migrationErrors = append(migrationErrors, err)
		}
	}
	if err := db.AutoMigrate(&model.FileShare{}); err != nil {
		if isIgnoreableError(err) {
			SystemLogger.Debug("FileShare model migration: ignored constraint error", zap.Error(err))
		} else {
			SystemLogger.Warn("FileShare model migration warning", zap.Error(err))
			migrationErrors = append(migrationErrors, err)
		}
	}
	if err := db.AutoMigrate(&model.UploadTask{}); err != nil {
		if isIgnoreableError(err) {
			SystemLogger.Debug("UploadTask model migration: ignored constraint error", zap.Error(err))
		} else {
			SystemLogger.Warn("UploadTask model migration warning", zap.Error(err))
			migrationErrors = append(migrationErrors, err)
		}
	}
	if err := db.AutoMigrate(&model.UploadChunk{}); err != nil {
		if isIgnoreableError(err) {
			SystemLogger.Debug("UploadChunk model migration: ignored constraint error", zap.Error(err))
		} else {
			SystemLogger.Warn("UploadChunk model migration warning", zap.Error(err))
			migrationErrors = append(migrationErrors, err)
		}
	}

	if len(migrationErrors) > 0 {
		SystemLogger.Info("database migrations completed with warnings", zap.Int("error_count", len(migrationErrors)))
	} else {
		SystemLogger.Info("database migrations completed successfully")
	}

	DB = db
}
